<!DOCTYPE html>
<!--
@license
Copyright (C) 2019 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-reviewer-suggestions-provider</title>

<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>

<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../../../test/common-test-setup.html"/>
<link rel="import" href="../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.html"/>
<script src="../gr-display-name-utils/gr-display-name-utils.js"></script>
<script src="gr-reviewer-suggestions-provider.js"></script>

<script>void(0);</script>

<test-fixture id="basic">
  <template>
    <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
  </template>
</test-fixture>

<script>
  suite('GrReviewerSuggestionsProvider tests', () => {
    let sandbox;
    let _nextAccountId = 0;
    const makeAccount = function(opt_status) {
      const accountId = ++_nextAccountId;
      return {
        _account_id: accountId,
        name: 'name ' + accountId,
        email: 'email ' + accountId,
        status: opt_status,
      };
    };
    let _nextAccountId2 = 0;
    const makeAccount2 = function(opt_status) {
      const accountId2 = ++_nextAccountId2;
      return {
        _account_id: accountId2,
        name: 'name ' + accountId2,
        status: opt_status,
      };
    };

    let owner;
    let existingReviewer1;
    let existingReviewer2;
    let suggestion1;
    let suggestion2;
    let suggestion3;
    let restAPI;
    let provider;

    let redundantSuggestion1;
    let redundantSuggestion2;
    let redundantSuggestion3;
    let change;

    setup(done => {
      owner = makeAccount();
      existingReviewer1 = makeAccount();
      existingReviewer2 = makeAccount();
      suggestion1 = {account: makeAccount()};
      suggestion2 = {account: makeAccount()};
      suggestion3 = {
        group: {
          id: 'suggested group id',
          name: 'suggested group',
        },
      };

      stub('gr-rest-api-interface', {
        getLoggedIn() { return Promise.resolve(true); },
        getConfig() { return Promise.resolve({}); },
      });

      restAPI = fixture('basic');
      change = {
        _number: 42,
        owner,
        reviewers: {
          CC: [existingReviewer1],
          REVIEWER: [existingReviewer2],
        },
      };
      sandbox = sinon.sandbox.create();
      return flush(done);
    });

    teardown(() => {
      sandbox.restore();
    });
    suite('allowAnyUser set to false', () => {
      setup(done => {
        provider = GrReviewerSuggestionsProvider.create(restAPI, change._number,
            Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.REVIEWER);
        provider.init().then(done);
      });
      suite('stubbed values for _getReviewerSuggestions', () => {
        setup(() => {
          stub('gr-rest-api-interface', {
            getChangeSuggestedReviewers() {
              redundantSuggestion1 = {account: existingReviewer1};
              redundantSuggestion2 = {account: existingReviewer2};
              redundantSuggestion3 = {account: owner};
              return Promise.resolve([redundantSuggestion1, redundantSuggestion2,
                redundantSuggestion3, suggestion1, suggestion2, suggestion3]);
            },
          });
        });

        test('makeSuggestionItem formats account or group accordingly', () => {
          let account = makeAccount();
          const account3 = makeAccount2();
          let suggestion = provider.makeSuggestionItem({account});
          assert.deepEqual(suggestion, {
            name: account.name + ' <' + account.email + '>',
            value: {account},
          });

          const group = {name: 'test'};
          suggestion = provider.makeSuggestionItem({group});
          assert.deepEqual(suggestion, {
            name: group.name + ' (group)',
            value: {group},
          });

          suggestion = provider.makeSuggestionItem(account);
          assert.deepEqual(suggestion, {
            name: account.name + ' <' + account.email + '>',
            value: {account, count: 1},
          });

          suggestion = provider.makeSuggestionItem({account: {}});
          assert.deepEqual(suggestion, {
            name: 'Anonymous',
            value: {account: {}},
          });

          provider._config = {
            user: {
              anonymous_coward_name: 'Anonymous Coward Name',
            },
          };

          suggestion = provider.makeSuggestionItem({account: {}});
          assert.deepEqual(suggestion, {
            name: 'Anonymous Coward Name',
            value: {account: {}},
          });

          account = makeAccount('OOO');

          suggestion = provider.makeSuggestionItem({account});
          assert.deepEqual(suggestion, {
            name: account.name + ' <' + account.email + '> (OOO)',
            value: {account},
          });

          suggestion = provider.makeSuggestionItem(account);
          assert.deepEqual(suggestion, {
            name: account.name + ' <' + account.email + '> (OOO)',
            value: {account, count: 1},
          });

          sandbox.stub(GrDisplayNameUtils, '_accountEmail',
              () => {
                return '';
              });

          suggestion = provider.makeSuggestionItem(account3);
          assert.deepEqual(suggestion, {
            name: account3.name,
            value: {account: account3, count: 1},
          });
        });

        test('getSuggestions', done => {
          provider.getSuggestions().then(reviewers => {
            // Default is no filtering.
            assert.equal(reviewers.length, 6);
            assert.deepEqual(reviewers,
                [redundantSuggestion1, redundantSuggestion2,
                  redundantSuggestion3, suggestion1, suggestion2, suggestion3]);
          }).then(done);
        });

        test('getSuggestions short circuits when logged out', () => {
          // API call is already stubbed.
          const xhrSpy = restAPI.getChangeSuggestedReviewers;
          provider._loggedIn = false;
          return provider.getSuggestions('').then(() => {
            assert.isFalse(xhrSpy.called);
            provider._loggedIn = true;
            return provider.getSuggestions('').then(() => {
              assert.isTrue(xhrSpy.called);
            });
          });
        });
      });

      test('getChangeSuggestedReviewers is used', done => {
        const suggestReviewerStub =
            sandbox.stub(restAPI, 'getChangeSuggestedReviewers')
                .returns(Promise.resolve([]));
        const suggestAccountStub =
            sandbox.stub(restAPI, 'getSuggestedAccounts')
                .returns(Promise.resolve([]));

        provider.getSuggestions('').then(() => {
          assert.isTrue(suggestReviewerStub.calledOnce);
          assert.isTrue(suggestReviewerStub.calledWith(42, ''));
          assert.isFalse(suggestAccountStub.called);
          done();
        });
      });
    });

    suite('allowAnyUser set to true', () => {
      setup(done => {
        provider = GrReviewerSuggestionsProvider.create(restAPI, change._number,
            Gerrit.SUGGESTIONS_PROVIDERS_USERS_TYPES.ANY);
        provider.init().then(done);
      });

      test('getSuggestedAccounts is used', done => {
        const suggestReviewerStub =
            sandbox.stub(restAPI, 'getChangeSuggestedReviewers')
                .returns(Promise.resolve([]));
        const suggestAccountStub =
            sandbox.stub(restAPI, 'getSuggestedAccounts')
                .returns(Promise.resolve([]));

        provider.getSuggestions('').then(() => {
          assert.isFalse(suggestReviewerStub.called);
          assert.isTrue(suggestAccountStub.calledOnce);
          assert.isTrue(suggestAccountStub.calledWith('cansee:42 '));
          done();
        });
      });
    });
  });
</script>
